﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Reflection.Emit;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace lan_file_transfer.Roads.tcp
{
    public class TcpRoads : Truck
    {
        private List<TcpClient> clientList;
        NetworkStream[] streamArray;
        NetworkStream mainStream;
        TcpClient mainClient;
        Task initMainConnThread;
        string serverIPaddress;
        /// <summary>
        /// 记录多线程链接是否已经创建
        /// </summary>
        bool multiThreadConnIsCreated_flag = false;
        //public TcpRoads(string localIP,int localPort=10192,string taskIP = null, int taskPort = 10192,bool local_is_server=true)
        public TcpRoads(string serverIP, int serverPort, bool local_is_server = true)
        {
            serverIPaddress = serverIP;
            initMainConnThread = Task.Run(() => {
                Dispose();
                mainClient = initTCP(serverIP, serverPort, local_is_server);
                mainStream = mainClient.GetStream();
                clientList.Add(mainClient);
                taskQueue.Enqueue(Task.Run(() =>
                {
                    rcv();
                }));
            });
            taskQueue.Enqueue(initMainConnThread);
        }
        /// <summary>
        /// 创建多线程连接
        /// </summary>
        /// <param name="sendThreadNum">发送线程数</param>
        /// <param name="rcvThreadNum">接收线程数</param>
        /// <returns>true：成功    false：失败</returns>
        public override bool connect(int threadNum = 1)
        {
            if(mainStream!=null)
            {
                if(multiThreadConnIsCreated_flag)
                {
                    log("本机已经创建多线程连接");
                    return false;
                }
                streamArray = new NetworkStream[threadNum];
                List<int> ports = new List<int>();
                int port = 10100;
                List<Task> mulitConnList = new List<Task>();
                while((port++ < 10200) &&(ports.Count < threadNum))
                {
                    if (portIsUseful(serverIPaddress, port))
                    {
                        mulitConnList.Add(Task.Run(() =>
                        {
                            TcpClient client = initTCP(serverIPaddress, port, true);
                            clientList.Add(client);
                            saveTcpStream(client.GetStream());
                        }));
                        ports.Add(port);
                        Thread.Sleep(100);
                    }
                }
                foreach(Task t in mulitConnList)
                {
                    taskQueue.Enqueue(t);
                }
                byte[] array = Encoding.ASCII.GetBytes("ports:" + string.Join(",",ports));
                //Task.WaitAll(mulitConnList.ToArray());
                Thread.Sleep(1000);
                mainStream.Write(array,0,array.Length);
                log("多端口server连已创建，等待连接");
                return true;
            }
            else
            {
                log("初始链接创建异常");
            }
            return false;
        }

        protected override void init()
        {
            clientList = new List<TcpClient>();

            base.init();
        }

        protected override void rcv()
        {
            byte[] data = new byte[sendDataLength];
            int length = 0;
            while ((length = mainStream.Read(data, 0, sendDataLength)) != 0)
            {
                //RCV_ACTION(data);
                analyzeCmd(Encoding.ASCII.GetString(data, 0, length));
            }
        }
        private void analyzeCmd(string cmd)
        {
            string[] array = cmd.Split(':');
            switch(array[0])
            {
                case "ports":
                    log($"收到ports信息：{cmd}");
                    string[] ports = array[1].Split(',');
                    streamArray = new NetworkStream[ports.Length];
                    foreach (string str in ports)
                    {
                        createTcpClientConn(Convert.ToInt32(str));
                    }
                    break;
                default:
                    log($"收到无效命令：{cmd}");
                    break;
            }
        }
        private void createTcpClientConn(int port)
        {
            try
            {
                TcpClient client = new TcpClient(serverIPaddress, port);
                clientList.Add(client);
                saveTcpStream(client.GetStream());
                log($"client创建成功，端口{port}");
            }
            catch(Exception)
            {
                log($"client创建失败，端口{port}");
            }
        }
        private void saveTcpStream(NetworkStream stream)
        {
            for (int i = 0; i < streamArray.Length; i++)
            {
                if (streamArray[i] == null)
                {
                    streamArray[i] = stream;
                    break;
                }else if ((i + 1) == streamArray.Length)
                {
                    log("save tcp stream fail");
                }
            }
        }
        protected override void send(byte[] data,int index)
        {
            streamArray[index].Write(data, 0, data.Length);
        }
        /// <summary>
        /// 输入配置信息，创建一个连接，返回client对象
        /// </summary>
        /// <param name="serverIP"></param>
        /// <param name="serverPort"></param>
        /// <param name="local_is_server"></param>
        /// <returns></returns>
        private TcpClient initTCP(string serverIP, int serverPort, bool local_is_server = true)
        {
            TcpClient client = new TcpClient();
            TcpListener server;
            if (local_is_server)
            {
                IPAddress localAddress;
                if (!IPAddress.TryParse(serverIP, out localAddress))
                {
                    log("本地地址异常");
                }
                server = new TcpListener(localAddress, serverPort);

                server.Start();
                log("server start"); 
                client = server.AcceptTcpClient();
                log($"server connected : local port {serverPort}");
            }
            else
            {
                client = new TcpClient(serverIP, serverPort);
                log("client connected");
            }
            return client;
        }
        private bool portIsUseful(string ip, int port)
        {
            try
            {
                TcpListener tcpListener = new TcpListener(IPAddress.Parse(ip),port);
            }catch(Exception)
            {
                return false;
            }
            return true;
        }
    }
}
